/*******************************************************************************
 * Copyright (c) 2001, 2002 Boris Pruessmann and others. All rights reserved.
 * This program and the accompanying materials are made available under the
 * terms of the Common Public License v0.5 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/cpl-v05.html
 * 
 * Contributors: Boris Pruessmann - Initial implementation.
 ******************************************************************************/
package net.sourceforge.perforce.core.internal.api;

import com.google.common.collect.Lists;

import net.sourceforge.perforce.api.IError;
import net.sourceforge.perforce.api.IPerforceCommand;
import net.sourceforge.perforce.core.PerforceCorePlugin;
import net.sourceforge.perforce.core.api.ISubmitResult;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;

import java.util.List;

/**
 * ClientUser object for the 'p4 submit' command.
 * 
 * @version $Revision: 488 $
 * @author <a href="mailto:bpruessmann@users.sourceforge.net">Boris
 *         Pruessmann</a>
 */
public class Submit extends AbstractPerforceCommand implements IPerforceCommand {
  // ---------------------------------------------------------------------------
  // Private Variables

  /** Stores the changespec. */
  private ChangeSpec changeSpec;
  /** Stores the result of the command. */
  private List<Result> resultList = Lists.newArrayList();

  // --------------------------------------------------------------- Public
  // Static Factory Methods

  /**
   * Convenience method for creating instances of Change.
   * 
   * @param changeSpec the change specification used for submitting.
   * @param monitor the monitor for progress feedback.
   * @return the new Submit instance.
   */
  public static final Submit newInstanceForOutput(ChangeSpec changeSpec, IProgressMonitor monitor) {
    MultiStatus status = new MultiStatus(PerforceCorePlugin.ID, IStatus.OK, "", null);
    return new Submit(status, changeSpec, monitor);
  }

  // ------------------------------------------------------------------------
  // Private Constructors

  /**
   * Constructor for Submit.
   * 
   * @param status the MultiStatus object.
   * @param changeSpec the changelist specification.
   * @param monitor the monitor for progress feedback.
   */
  private Submit(MultiStatus status, ChangeSpec changeSpec, IProgressMonitor monitor) {
    super(status, monitor);
    this.changeSpec = changeSpec;

    getProgressMonitor().beginTask("", changeSpec.getFileCount() * 1000); //$NON-NLS-1$
  }

  // -------------------------------------------------------- Public Methods
  // (IClientUserDelegate)

  @Override
  public String inputData(IError error) {
    return changeSpec.toString();
  }

  @Override
  public void outputError(String errorString) {
    IStatus tempStatus = PerforceStatus.decode(errorString, IStatus.OK);
    IStatus[] children = getMultiStatus().getChildren();

    MultiStatus multiStatus =
        new MultiStatus(PerforceCorePlugin.ID, IStatus.ERROR, children, tempStatus.getMessage(),
            null);
    setMultiStatus(multiStatus);
  }

  @Override
  public void outputInfo(char level, String infoString) {
    IStatus tempStatus = PerforceStatus.decode(infoString, IStatus.OK);

    if (level == '0') {
      int start = infoString.indexOf("//"); //$NON-NLS-1$
      int stop = infoString.lastIndexOf('#');

      if (tempStatus.getCode() == PerforceStatus.REFRESHING.getCode()) {
        String file = infoString.substring(0, infoString.lastIndexOf('#'));

        for (Result result : resultList) {
          if (result.getDepotFilename().equals(file)) {
            result.setRefreshed(true);
          }
        }
      } else if (tempStatus.getCode() == PerforceStatus.MUST_RESOLVE_BEFORE_SUBMITTING.getCode()) {
        stop = infoString.indexOf(" - must resolve "); //$NON-NLS-1$

        Result result = new Result();

        result.setDepotFilename(infoString.substring(start, stop));
        resultList.add(result);

        getProgressMonitor().subTask("Processing " + result.getDepotFilename());
        getProgressMonitor().worked(1000);
      } else if (tempStatus.getCode() == PerforceStatus.MUST_RESOLVE.getCode()) {
      } else if (start != -1 && stop != -1 && start < stop) {
        Result result = new Result();

        result.setDepotFilename(infoString.substring(start, stop));
        result.setAction(infoString.substring(0, start - 1));

        resultList.add(result);

        getProgressMonitor().subTask("Processing " + result.getDepotFilename());
        getProgressMonitor().worked(1000);
      } else {
        getProgressMonitor().subTask(infoString);
      }
    }

    getMultiStatus().merge(tempStatus);
  }

  @Override
  public void finished() {
    getProgressMonitor().done();
  }


  // ----------------------------------------------------------- Public Methods
  // (IPerforceCommand)

  public String getCommand() {
    return "submit"; //$NON-NLS-1$
  }

  @Override
  public IStatus getStatus() {
    return getMultiStatus();
  }

  //----------------------------------------------------------------------------
  // -- Public Methods

  /**
   * Returns an array of result objects.
   * 
   * @return affected files.
   */
  public ISubmitResult[] getResult() {
    return resultList.toArray(new ISubmitResult[resultList.size()]);
  }

  // -----------------------------------------------------------------------
  // Public Nested Classes

  /** Represents the result of the submit action. */
  public static class Result implements ISubmitResult {
    // -----------------------------------------------------------------------
    // Private Variables

    /** Stores the depot filename of the resource. */
    private String depotFilename;
    /** Stores the performed action. */
    private String action;
    /** Stores whether the item was refreshed or not. */
    private boolean refreshed;

    //--------------------------------------------------------------------------
    // Public Methods

    /** @see ISubmitResult#getDepotFilename() */
    public String getDepotFilename() {
      return depotFilename;
    }

    /** @see ISubmitResult#getAction() */
    public String getAction() {
      return action;
    }

    /** @see ISubmitResult#isRefreshed() */
    public boolean isRefreshed() {
      return refreshed;
    }

    @Override
    public String toString() {
      String result = action + " " + depotFilename;
      if (refreshed) {
        result += " [refreshed]";
      }

      return result;
    }

    // -------------------------------------------------------------------------
    // Private Methods

    /**
     * Sets the depot filename.
     * 
     * @param depotFilename the new depot filename.
     */
    private void setDepotFilename(String depotFilename) {
      this.depotFilename = depotFilename;
    }

    /**
     * Sets the action.
     * 
     * @param action the new action.
     */
    private void setAction(String action) {
      this.action = action;
    }

    /**
     * Sets the value of the refreshed flag.
     * 
     * @param refreshed the new value.
     */
    private void setRefreshed(boolean refreshed) {
      this.refreshed = refreshed;
    }
  }
}
